/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2015 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = rmi_core.c                                                    */
/*  NOTE      =                                                               */
/*  DATE      = 2015/06/19 by geyh                                            */
/******************************************************************************/
#include <stdio.h>
#include <sys/time.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"
#include "frsutl.h"
#include "frct_comm.h"
#include "rmi_parse.h"
#include "rmi_core.h"

#define RMI_MAX_SIZE                65535


/*******************************************************************************
*  FUNC     :  rmi私有信息创建
*  ARGS     :  void
*           :
*  RTN      :  NULL                     失败
*           :  p_st_private             成功
*  NOTE     :
*******************************************************************************/
FR_STATIC L7session_rmi_private* __rmi_private_create(void)
{
    L7session_rmi_private *p_st_private = NULL;

    p_st_private = (L7session_rmi_private*)frmalloc(sizeof(L7session_rmi_private));
    if(p_st_private == NULL)
    {
        FRLOG_ERROR_DETAIL("MEMORY ERR");
        return NULL;
    }

    memset(p_st_private, 0x00, sizeof(L7session_rmi_private));

    p_st_private->p_st_data = bytebuff_creat();
    if(p_st_private->p_st_data == NULL)
    {
        FRLOG_ERROR_DETAIL("MEMORY ERR");
        frfree(p_st_private);
        return NULL;
    }
    p_st_private->i_flag_response_required = 1;

    return p_st_private;

}

/*******************************************************************************
*  FUNC     :  private信息初始化
*  ARGS     :  p_private_session
*           :
*  RTN      :  FR_SUCC
*           :  FR_FAIL
*  NOTE     :
*******************************************************************************/
int rmi_session_reset(void *p_private_session)
{
    L7session_rmi_private *p_st_private = (L7session_rmi_private*)p_private_session;

    if(p_st_private)
    {
        if(p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if(p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if(p_st_private->p_lst_comm_tmp)
            frreport_body_l7list_free(&p_st_private->p_lst_comm_tmp);

        if(p_st_private->p_lst_req_tmp)
            frreport_body_l7list_free(&p_st_private->p_lst_req_tmp);

        if(p_st_private->p_st_data)
            bytebuff_free(&p_st_private->p_st_data);

        memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));

        p_st_private->p_st_data = bytebuff_creat();
        if(p_st_private->p_st_data == NULL)
        {
            frfree(p_st_private);
            return FR_FAIL;
        }

        p_st_private->i_flag_response_required = 1;
        p_st_private->i_args_num = 0;

        if(p_st_private->p_transaction_title)
        {
            frfree(p_st_private->p_transaction_title);
            p_st_private->p_transaction_title = NULL;
        }

        if(p_st_private->p_func)
        {
            frfree(p_st_private->p_func);
            p_st_private->p_func = NULL;
        }
    }
    return FR_SUCC;

}

/*******************************************************************************
*  FUNC     :  判断是否为RMI协议
*  ARGS     :  p_st_conn                CT信息
*           :  p_st_packet             入力参数
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    char *p_data_in = NULL;
    unsigned int ui_data_len = 0;
    char c_opt;
    int i_flag_direct = 0;
    unsigned short us_data_len = 0;
    int i_ret_fun = 0;

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len == 0)
        return APM_L7_IS_NO;

    p_data_in = p_st_packet->p_payload;
    ui_data_len = p_st_packet->ui_payload_len;
    c_opt = *p_data_in;

    switch (c_opt)
    {
        case '\x4a':
            //判断长度是否为7
            if(ui_data_len != 7)
                return APM_L7_IS_NO;

            //Version Protocol
            if(memcmp(p_data_in, "JRMI", 4) != 0)
                return APM_L7_IS_NO;
            p_data_in += 4;

            //跳过version /x00/x01
            p_data_in += 2;

            //Protocol
            if(*p_data_in < '\x4a' || *p_data_in > '\x4d')
                return APM_L7_IS_NO;

            i_flag_direct = FR_DIRECT_CLIENT2SRV;

            break;

        case '\x4e':
            //IP string
            if(us_data_len < 3)
                return APM_L7_IS_NO;

            us_data_len |= *(p_data_in + 1);
            us_data_len = us_data_len << 8;
            us_data_len |= *(p_data_in + 2);

            //PORT int
            us_data_len += 4;
            if(us_data_len != ui_data_len - 3)
                return APM_L7_IS_NO;

            i_flag_direct = FR_DIRECT_CLIENT2SRV;

            break;

        case '\x50':
            //判断长度最小为3
            if(ui_data_len < 3)
                return APM_L7_IS_NO;

            p_data_in++;

            //判断magic
            if(memcmp(p_data_in, "\xac\xed", 2) != 0)
                return APM_L7_IS_NO;

            i_flag_direct = FR_DIRECT_SRV2CLIENT;

            break;

        default:
            return APM_L7_IS_NO;
    }

    //长连接对应
    i_ret_fun = frct_get_direct_known(p_st_conn);
    if(i_ret_fun == FR_DIRECT_UNKNOWN)
    {
        if(i_flag_direct == FR_DIRECT_CLIENT2SRV)
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
        else
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
    }

    return APM_L7_IS_YES;
}




int __rmi_data_report(Conntrack *p_st_conn, Frhash_header *p_st_hash_report, L7session_rmi_private *p_st_private, int i_use_request)
{
    int i_ret = 0;
    Frreport_data* p_st_report_data = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    unsigned long ul_tmp = 0;

    if(p_st_hash_report == NULL || p_st_private == NULL)
        return FR_FAIL;

    p_st_l4_trans = &p_st_private->st_l4_trans;

    if(i_use_request)
    {
        //数据链表  设置为request
        i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_req, p_st_conn);
        if(i_ret == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_request_time_first_byte) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_l4_trans->st_request_time) == FR_FAIL)
            goto ERROR;

        ul_tmp = frtime_diff(&p_st_l4_trans->st_request_time_first_byte, &p_st_l4_trans->st_request_time);
        if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
            goto ERROR;

        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
        if(p_st_report_data == NULL)
            goto ERROR;

        p_st_private->p_lst_comm_tmp = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_private->p_st_body_data_req);
        if(p_st_private->p_lst_comm_tmp == NULL)
            goto ERROR;

        p_st_private->p_lst_req_tmp = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_req);
        if(p_st_private->p_lst_req_tmp == NULL)
            goto ERROR;

        if(frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
            goto ERROR;
        p_st_private->p_st_body_data_req = NULL;

        if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto ERROR;

        return FR_SUCC;
    }
    else
    {
        //数据链表  设置为response
        if(p_st_private->p_lst_comm_tmp == NULL)
        {
            i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_resp, p_st_conn);
            if(i_ret == FR_FAIL)
                goto ERROR;

        }
        else
        {
            //comm
            if(FRREPORT_BODY_L7LIST_SET_COMM(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_comm_tmp) == FR_FAIL)
                goto ERROR;

            //把req数据链表添加到resp中
            if(FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_req_tmp) == FR_FAIL)
                goto ERROR;

            ul_tmp = frtime_diff(&p_st_l4_trans->st_request_time, &p_st_l4_trans->st_response_time_first_byte);
            if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
                goto ERROR;

        }

        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
            goto ERROR;

        ul_tmp = frtime_diff(&p_st_l4_trans->st_response_time_first_byte, &p_st_l4_trans->st_response_time);
        if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_CODE, 0) == FR_FAIL)
            goto ERROR;

        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if(p_st_report_data == NULL)
            goto ERROR;

        if(frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_resp) == FR_FAIL)
            goto ERROR;
        p_st_private->p_st_body_data_resp = NULL;

        if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto ERROR;

        return FR_SUCC;
    }

    return FR_SUCC;

ERROR:

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_private->p_lst_comm_tmp)
        frreport_body_l7list_free(&p_st_private->p_lst_comm_tmp);

    if(p_st_private->p_lst_req_tmp)
        frreport_body_l7list_free(&p_st_private->p_lst_req_tmp);

    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  数据解析
*  ARGS     :  p_st_conn                ct信息
*           :  p_st_packet             入力参数
*           :  p_st_hash_report         hash表
*  RTN      :  APM_L7_ANALYZE_SUCC
*           :  APM_L7_ANALYZE_FAIL
*           :  APM_L7_ANALYZE_TODO
*  NOTE     :
*******************************************************************************/
int rmi_analysis(Conntrack *p_st_conn
                  , Apm_packet *p_st_packet
                  , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_session *p_st_session = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    L7session_rmi_private *p_st_private = NULL;

    if(p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //从SYN包开始解析
    if(p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        rmi_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = __rmi_private_create();

        if(p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
        return APM_L7_ANALYZE_SUCC;
    }
    else if(p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN)
    {
        rmi_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    if(p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __rmi_private_create();
        if(p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
        //设置UUID
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_rmi_private*)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if(p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        if(p_st_private->i_flag_cont == 2)
        {
            p_st_private->i_flag_cont = 0;
            i_ret = rmi_session_reset(p_st_private);
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;
        }

        if(p_st_l4_trans->st_request_time_first_byte.tv_sec == 0
            && p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
        {
            p_st_private->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
            if(p_st_private->p_st_body_data_req == NULL)
                return APM_L7_ANALYZE_FAIL;

            //st_request_time_first_byte
            p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

            //seq ++
            p_st_private->ul_seq = frct_seq_increase(p_st_conn);
        }
        //st_request_time
        p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

        /* 请求的字节数 */
        p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

        i_ret = bytebuff_add(p_st_private->p_st_data, p_st_packet->p_payload, p_st_packet->ui_payload_len);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;

        if(p_st_private->p_st_data->ui_all_len > RMI_MAX_SIZE || p_st_l4_trans->st_response_time_first_byte.tv_sec)
            return APM_L7_ANALYZE_FAIL;

        p_st_private->i_use_request = FR_YES;
        i_ret = rmi_parse(p_st_private->p_st_data, p_st_private->p_st_body_data_req, p_st_private);
        if(i_ret != APM_L7_ANALYZE_SUCC)
        {
            if(i_ret == APM_L7_ANALYZE_FAIL)
            {
                rmi_session_destroy(p_st_private);
                p_st_session->p_session_private = NULL;
            }

            return i_ret;
        }

        //todo
        if(p_st_private->i_flag_report)
        {
            i_ret = __rmi_data_report(p_st_conn, p_st_hash_report, p_st_private, FR_YES);
            if(i_ret == FR_FAIL)
                goto ERROR;

            if(p_st_private->p_st_data)
                bytebuff_free(&p_st_private->p_st_data);

            p_st_private->p_st_data = bytebuff_creat();
            if(p_st_private->p_st_data == NULL)
                return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            frreport_body_free(&p_st_private->p_st_body_data_req);

            if(p_st_private->p_st_data)
                bytebuff_free(&p_st_private->p_st_data);

            p_st_private->p_st_data = bytebuff_creat();
            if(p_st_private->p_st_data == NULL)
                return APM_L7_ANALYZE_FAIL;

            memset(p_st_l4_trans, 0x00, sizeof(L4_transaction));
        }

        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }
    else//response
    {
        if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 &&
            p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
        {
            p_st_private->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
            if(p_st_private->p_st_body_data_resp == NULL)
                return APM_L7_ANALYZE_FAIL;

            //应答发起时间戳
            p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

            //首包时间
            if(p_st_l4_trans->st_request_time_first_byte.tv_sec != 0)
                p_st_l4_trans->ul_response_time_firstbyte_us = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_response_time_first_byte));
            else
                p_st_l4_trans->ul_response_time_firstbyte_us = 0;

        }
        //st_response_time
        p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
        /* 请求的字节数 */
        p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

        //添加到bytebyff
        i_ret = bytebuff_add(p_st_private->p_st_data, p_st_packet->p_payload, p_st_packet->ui_payload_len);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;

        if(p_st_private->p_st_data->ui_all_len > RMI_MAX_SIZE)
            return APM_L7_ANALYZE_FAIL;

        p_st_private->i_use_request = FR_NO;
        i_ret = rmi_parse(p_st_private->p_st_data, p_st_private->p_st_body_data_resp, p_st_private);
        if(i_ret != APM_L7_ANALYZE_SUCC)
        {
            if(i_ret == APM_L7_ANALYZE_FAIL)
            {
                rmi_session_destroy(p_st_private);
                p_st_session->p_session_private = NULL;
            }

            return i_ret;
        }

        //todo
        if(p_st_private->i_flag_report)
        {
            if(p_st_private->ul_seq == 0)
                p_st_private->ul_seq = frct_seq_increase(p_st_conn);

            i_ret = __rmi_data_report(p_st_conn, p_st_hash_report, p_st_private, FR_NO);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }
        else
        {
            frreport_body_free(&p_st_private->p_st_body_data_resp);
        }

        i_ret = rmi_session_reset(p_st_private);
        if(i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;

        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    }

ERROR:
    if(p_st_private)
        rmi_session_destroy(p_st_private);
    p_st_session->p_session_private = NULL;

    return APM_L7_ANALYZE_FAIL;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session
*           :
*  RTN      :  FR_SUCC
*           :
*  NOTE     :
*******************************************************************************/
int rmi_session_destroy(void *p_private_session)
{
    L7session_rmi_private *p_st_private = (L7session_rmi_private*)p_private_session;

    if(p_st_private)
    {
        if(p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if(p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if(p_st_private->p_lst_comm_tmp)
            frreport_body_l7list_free(&p_st_private->p_lst_comm_tmp);

        if(p_st_private->p_lst_req_tmp)
            frreport_body_l7list_free(&p_st_private->p_lst_req_tmp);

        if(p_st_private->p_st_data)
            bytebuff_free(&p_st_private->p_st_data);

        if(p_st_private->p_transaction_title)
            frfree(p_st_private->p_transaction_title);

        if(p_st_private->p_server)
            frfree(p_st_private->p_server);

        if(p_st_private->p_func)
            frfree(p_st_private->p_func);

        frfree(p_st_private);
    }
    return FR_SUCC;

}

